using System;

namespace AdvancedGod.People.Couples
{
  /// <summary>
  /// Performs coupling of two peoples (without children creation)
  /// </summary>
  public class CouplingPerformer
  {
    #region private static vars
    /// <summary>
    /// Single instance of coupling performer
    /// </summary>
    private static CouplingPerformer instance;
    #endregion

    #region public static properties
    /// <summary>
    /// Getter for single instance of performer
    /// </summary>
    public static CouplingPerformer Instance
    {
      get { return instance ?? (instance = new CouplingPerformer()); }
    }

    /// <summary>
    /// Default constructor (hided)
    /// </summary>
    private CouplingPerformer() { }
    #endregion

    #region public methods
    /// <summary>
    /// tries to couple two humans
    /// </summary>
    /// <param name="firstHuman">first human</param>
    /// <param name="secondHuman">second human</param>
    /// <exception cref="SameSexException">throws if humans have same 
    /// sex</exception>
    /// <returns></returns>
    public bool TryCouple(Human firstHuman, Human secondHuman)
    {
      if (firstHuman.Sex == secondHuman.Sex)
      {
        throw new SameSexException(firstHuman.Sex);
      }
      return Couple(firstHuman, secondHuman);

    }
    #endregion public methods

    #region private methods
    /// <summary>
    /// Couples peoples. 
    /// </summary>
    /// <param name="firstHuman">first people</param>
    /// <param name="secondHuman">second people</param>
    /// <returns>true if coupling results with success, 
    /// false otherwise</returns>
    private bool Couple(Human firstHuman, Human secondHuman)
    {
      if (!TestIfFirstLikeSecond(firstHuman, secondHuman))
      {
        return false;
      }
      if (!TestIfFirstLikeSecond(secondHuman, firstHuman))
      {
        return false;
      }
      return true;
    }

    /// <summary>
    /// Tests if first people likes second people
    /// </summary>
    /// <param name="firstHuman">first people</param>
    /// <param name="secondHuman">second people</param>
    /// <returns>true if first people likes second, false otherwise</returns>
    private bool TestIfFirstLikeSecond(Human firstHuman, Human secondHuman)
    {
      var random = new Random();
      double probability = FindProbability(firstHuman, secondHuman);
      double randomDouvle = random.NextDouble();

      return randomDouvle <= probability;
    }

    /// <summary>
    /// Gets probaility of liking (first prople likes second) from attribute with 
    /// pertient pair
    /// </summary>
    /// <param name="firstHuman">first human (test if its like second) </param>
    /// <param name="secondHuman">second human (tests if it liked by first)</param>
    /// <returns>value of probability of liking from 0.0 to 1.0</returns>
    private double FindProbability(Human firstHuman, Human secondHuman)
    {
      CoupleAttribute attribute = 
        CouplingUtils.FindPertientCoupleAttribute(firstHuman, secondHuman);
      return attribute.Probability;
    }

    #endregion private methods

  }
}